import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:geomancy/enums/index.dart';
import 'package:geomancy/models/base_model.dart';
import 'package:geomancy/models/common_model.dart';
import 'package:geomancy/providers/user_provider.dart';
import 'package:geomancy/tools/config.dart';
import 'package:geomancy/tools/http.dart';
import 'package:geomancy/tools/utils.dart';
import 'package:provider/provider.dart';
import 'package:qiniu_flutter_sdk/qiniu_flutter_sdk.dart';
import 'package:image/image.dart' as img;

BaseOptions options = BaseOptions(
  //七牛云API
  baseUrl: 'http://ai.qiniuapi.com',
  connectTimeout: const Duration(seconds: 30),
  receiveTimeout: const Duration(seconds: 30),
  contentType: Headers.jsonContentType,
  responseType: ResponseType.plain,
);
class QiNiuHttp {
  static final Dio _dio = Dio(options);

  static Future<Response> request(
      Method method,
      String path,
      {
        dynamic params,
        required String token,
      }
  ) async {
    _dio.options.headers = {
      'Authorization': token,
    };
    try {
      dynamic data;
      dynamic queryParameters;
      if (method == Method.GET) {
        queryParameters = params;
      }
      if (method == Method.POST) {
        data = params;
      }
      Response response = await _dio.request(path,
          data: data,
          queryParameters: queryParameters,
          options: Options(method: methodValues[method])
      );
      return response;
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout || e.type == DioExceptionType.receiveTimeout || e.type == DioExceptionType.sendTimeout) {
        Timer(const Duration(seconds: 1), () {
          EasyLoading.dismiss();
          EasyLoading.showToast('网络请求超时');
        });
        rethrow;
      }
      rethrow;
    }
  }
}

class QiNiu {
  // 七牛云外链地址
  static const String _baseUrl = LocalConfig.qiNiuBaseUrl;
  // 存储上传用的token
  static String? _token;
  // 生成魔法参数需要的key
  static String? _key;
  // 创建 storage 对象
  static final Storage _storage = Storage();
  // 创建putController对象
  static PutController? _putController;
  static QiNiuResponseModel? _response;

  static get getKey => _key;


  //获取key
  static _getKey(BuildContext context, {
    //userAvatar:用户头像 feedback:意见反馈
    required UploadBucketType type,
    required File file
  }) {
    final List<String> tmpList = file.path.split('.');
    final ext = tmpList[tmpList.length-1];
    final now = DateTime.now();
    final time = now.millisecondsSinceEpoch.toString();
    final fullDate = Utils.formatFullDate(now);
    final user = context.read<UserProvider>().getUserInfo;
    switch (type) {
      case UploadBucketType.userAvatar:
        _key = 'user/avatar/${user?.id}/$fullDate/$time.$ext';
        break;
      case UploadBucketType.feedback:
        _key = 'feedback/${user?.id}/$fullDate/$time.$ext';
        break;
      default:
        break;
    }
  }

  //获取上传token
  static Future _getUploadToken(BuildContext context) async {
    try {
      final data = await Fetch.request(Method.GET, '/upload/token?key=$_key', context: context);
      final result = CommonModel.fromJson(json.decode(data.data));
      if (result.code == 200) {
        _token = result.data;
      }
    } catch(e) {
      //...
    }
  }

  // 取消当前正在上传任务
  static cancelUploadFile() {
    _putController?.cancel();
  }

  //图片审核，马上返回结果
  static Future<bool> censorImage(BuildContext context, String url) async {
    try {
      final data = await Fetch.request(Method.POST, '/upload/qiniu/sign', params: {
        "uri": url,
        "type": 'pic'
      }, context: context);
      final result = CommonModel.fromJson(json.decode(data.data));
      if (result.code == 200) {
        final sensorResult = jsonDecode(result.data);
        if (sensorResult['suggestion'] != 'block') {//审核不通过
          return true;
        }
      }
      return false;
    } catch(e) {
      return false;
    }
  }

  //通过File计算出图片的Size信息
  static Future<Size?> getImageSize(file) async {
    final bytes = await file.readAsBytes();
    final image = img.decodeImage(bytes);
    if (image != null) {
      return Size(image.width.toDouble(), image.height.toDouble());
    }
  }

  static _fetch(File file) async {
    // 使用 storage 的 putFile 对象进行文件上传
    try {
      if (_token == null) return;
      final list = file.absolute.path.split('/');
      final fName = list[list.length - 1];
      _putController = PutController();
      final PutOptions options = PutOptions(key: _key, controller: _putController);
      final List<String> tmpList = file.path.split('.');
      PutResponse response = await _storage.putFile(file, _token!, options: options);
      final rawData = response.rawData;
      final Size? calculateSize = await getImageSize(file);
      final double w = calculateSize?.width ?? double.parse(rawData['width'].toString());
      final double h = calculateSize?.height ?? double.parse(rawData['height'].toString());
      final double ratio = w / h;
      _response = QiNiuResponseModel(
          url: _baseUrl + rawData['key'],
          key: rawData['key'],
          width: w.toString(),
          height: h.toString(),
          ratio: ratio,
          fsize: rawData['fsize'],
          fname: fName,
          mimeType: rawData['mimeType'],
          ext: rawData['ext'],
          type: qiNiuMediaTypeValues[QiNiuMediaType.image]
      );
    } catch (error) {
      cancelUploadFile();
      rethrow;
    }
  }

  // 上传图片
  static Future<QiNiuResponseModel?> uploadImage(BuildContext context, {
    required File file,
    required UploadBucketType type,
  }) async {
    _getKey(context, type: type, file: file);
    await _getUploadToken(context);
    await _fetch(file);
    return _response;
  }
}